#ifndef _VL_RTSP_MEDIA_SOURCE__H_
#define _VL_RTSP_MEDIA_SOURCE__H_

#include "defs.h"
#include "rtp.h"
#include "utils/buffer.h"
#include "utils/queue_thread.h"
#include "utils/sync_code.h"
#include <unordered_map>

namespace VLRTSP {

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 11:45:28
 * 
 * 声明 MediaSession
 */
class MediaSession;

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 14:14:02
 * 
 * 媒体资源数据
 */
struct MediaSourceData {
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:16:58
	 * 
	 * 构造函数
	 * @param buffer    数据缓冲
	 * @param timestamp 时间戳
	 */
	explicit MediaSourceData(Buffer* buffer, uint32_t timestamp): buffer(buffer) {
		this->timestamp = timestamp;
	}
	
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:14:27
	 * 
	 * 数据缓冲
	 */
	std::shared_ptr<Buffer> buffer;
	
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:14:48
	 * 
	 * 时间戳
	 */
	uint32_t timestamp;
};

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 11:19:02
 * 
 * RTSP 媒体资源
 * 可将媒体资源添加到媒体会话 [MediaSession] 中
 * 
 *  MediaSource ───────┐
 *                     │
 *                     │
 *                     │ RTP Frame
 *  MediaSource ───────┼───────────► MediaSession ────────────► Socket
 *                     │
 *                     │
 *                     │
 *  ........... ───────┘
 *  
 */
class MediaSource {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:25:21
	 * 
	 * RTP 发送回调
	 */
	using RTPFrameSendCallback = std::function<void(std::shared_ptr<RTPFrame>&)>;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-13 16:17:58
	 * 
	 * 构造函数
	 */
	explicit MediaSource();
	
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-13 16:18:03
	 * 
	 * 析构函数
	 */
	~MediaSource();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:27:42
	 * 
	 * 添加 RTP 帧发送回调
	 * @param callback RTP 帧发送回调
	 * @return 回调编号
	 */
	uint32_t addFrameSendCallback(RTPFrameSendCallback callback);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:33:04
	 * 
	 * 移除 RTP 帧发送回调
	 * @param code 回调编号
	 */
	void removeFrameSendCallback(uint32_t code);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-07 16:54:49
	 * 
	 * 发送媒体资源数据
	 * @param sourceData 媒体资源数据
	 * 
	 */
	void sendFrame(MediaSourceData* sourceData);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-13 16:49:32
	 * 
	 * 构建媒体资源 SDP 段
	 * @param buffer 字节缓冲区
	 */
	virtual void buildSourceSDP(Buffer* buffer) {}

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-13 16:53:13
	 * 
	 * 获取媒体资源 Id
	 * @return 媒体资源 Id
	 */
	uint32_t getSouceId();

protected:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:18:33
	 * 
	 * 处理数据缓冲，组装成 RTP 帧，通过 [sendRTPFrame] 进行发送
	 * @param data 外部传来的数据
	 */
	virtual void onHandleDataBuffer(std::shared_ptr<MediaSourceData>& data) {}

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-10 15:57:04
	 * 
	 * 获取载荷类型
	 * @return 返回载荷类型，参照 [PayloadType] 枚举
	 */
	virtual PayloadType getPayloadType() const { return SourceType_Unknown; }

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 15:34:30
	 * 
	 * 填充 RTP 头部
 	 * @param buffer RTP 帧字节缓冲区
	 * @param timestamp 帧时间戳
	 * @param isLast 如果是最后一个包，该值为 true(适用于分包处理)
	 */
	void fillRTPHeader(Buffer* buffer, uint32_t timestamp, bool isLast = true);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-10 15:53:33
	 * 
	 * 发送 RTP 帧
	 * @param frame RTP 帧指针
	 */
	void sendRTPFrame(std::shared_ptr<RTPFrame> frame);

private:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-07 11:46:20
	 * 
	 * 声明 MediaSession 为友元类，操作内部私有方法
	 */
	friend class MediaSession;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-07 11:47:23
	 * 
	 * 贴附上 MediaSession
	 * @param session 媒体会话
	 * @param sourceId 媒体资源 Id
	 */
	void _attachSession(MediaSession* session, uint32_t sourceId);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:09:05
	 * 
	 * 接收到消息队列发送来的数据
	 * @param data 媒体资源数据
	 */
	void _onRecvBuffer(std::shared_ptr<MediaSourceData>& data);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-13 16:17:28
	 * 
	 * 判断当前媒体资源是否贴附上媒体会话
	 */
	bool isAttached;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 15:38:07
	 * 
	 * RTP 头部数据
	 */
	RTPHeader rtpHeader;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 15:55:43
	 * 
	 * RTP 头部同步码
	 */
	SyncCode seqCode;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-07 11:43:35
	 * 
	 * 媒体会话
	 */
	MediaSession* mediaSession;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-07 12:04:36
	 * 
	 * 资源 Id
	 */
	uint32_t sourceId;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:29:14
	 * 
	 * 回调锁
	 */
	std::mutex callbackMutex;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:27:12
	 * 
	 * 回调发号机
	 */
	SyncCode syncCode;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 11:56:01
	 * 
	 * 媒体资源数据消息队列
	 */
	QueueThread<MediaSourceData> handleThread;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-01-14 14:26:28
	 * 
	 * RTP 发送回调接口映射表
	 */
	std::unordered_map<uint32_t, RTPFrameSendCallback> callbackMap;
};

}

#endif //_VL_RTSP_MEDIA_SOURCE__H_
